<template>
  <v-form
    ref="form"
    v-model="valid"
    @submit.prevent
  >
    <v-row no-gutters>
      <!-- Label -->
      <v-col
        cols="12"
        sm="5"
        align-self="center"
        class="text-body-1 py-0"
        v-html="label">
      </v-col>

      <!-- Current value -->
      <v-col
        class="py-0"
      >

        <v-text-field
          v-model="internalValue"
          :suffix="suffix"
          :rules="textRules"
          :readonly="isLocked"
          :disabled="disabled || loading || isLocked"
          :step="step"
          @change="handleChange($event)"
          @focus="$event.target.select()"
          @click="keyboard=true"
          class="v-input--text-right"
          type="number"
          dense
          single-line
          outlined
          hide-details
        >
          <template v-slot:prepend>
            <v-btn
              v-if="isMobile"
              icon
              small
              :disabled="false"
              @click="lockState = !lockState"
              style="margin-top: -4px;"
            >
              <v-icon small v-if="isLocked">$pencil</v-icon>
              <v-icon small v-else>$lockReset</v-icon>
            </v-btn>

            <app-btn
              v-if="resetValue !== undefined"
              @click="handleReset"
              :disabled="disabled"
              style="margin-top: -4px;"
              color=""
              icon
              small
            >
              <v-icon small>$reset</v-icon>
            </app-btn>

          </template>
        </v-text-field>
      </v-col>
    </v-row>

    <v-slider v-if="!isScreen"
      v-model="internalValue"
      :rules="rules"
      :min="min"
      :max="internalMax"
      :step="step"
      :disabled="disabled || loading || isLocked || overridden"
      @change="handleChange($event)"
      ref="slider"
      dense
      hide-details
    >
    </v-slider>
    <AppNumberKeyboardDialog :number="internalValue" v-model="keyboard" @change="keyboardChange"></AppNumberKeyboardDialog>
  </v-form>
</template>

<script lang="ts">
import { Component, Prop, Watch, Mixins, Ref } from 'vue-property-decorator'
import VSlider from 'vuetify/lib/components/VSlider.vue'
import StateMixin from '@/mixins/state'
import { VForm } from '@/types/vuetify'
import AppNumberKeyboardDialog from '@/components/ui/AppNumberKeyboardDialog.vue'

@Component({
  components: { AppNumberKeyboardDialog }
})
export default class AppSlider extends Mixins(StateMixin) {
  @Prop({ type: Number, required: true })
  public value!: number

  @Prop({ type: Number, required: false })
  public resetValue!: number;

  @Prop({ type: String, required: true })
  public label!: string

  @Prop({ type: Array, default: () => { return [] } })
  public rules!: []

  @Prop({ type: Boolean, default: false })
  public disabled!: boolean

  @Prop({ type: Boolean, default: false })
  public locked!: boolean

  @Prop({ type: Boolean, default: false })
  public loading!: boolean

  @Prop({ type: Number, default: 0 })
  public min!: number;

  @Prop({ type: Number, default: 100 })
  public max!: number;

  @Prop({ type: Boolean, default: false })
  public overridable!: boolean;

  @Prop({ type: Number, default: 1 })
  public step!: number;

  @Prop({ type: String })
  public suffix!: string;

  @Ref('slider')
  slider!: VSlider;

  @Ref('form')
  form!: VForm;

  valid = true
  lockState = false
  overridden = false
  internalValue = this.value
  internalMax = this.max
  pending = false

  keyboard = false

  // If the parent updates the value.
  @Watch('value')
  onValue (value: string | number) {
    value = +value
    if (value !== this.internalValue) {
      this.internalValue = +value
    }
    this.pending = false
  }

  // If one of our controls updates the value.
  @Watch('internalValue')
  onInternalValue (value: string | number) {
    if (this.valid) {
      if (
        value > this.max &&
        this.overridable
      ) {
        // This is overridable, and the user wants to increase
        // past the given max. So, disable the slider - and let it be.
        this.overridden = true
        this.internalMax = +value
      } else {
        // This is not overridable, or the user has reverted back to a value
        // within the given max. So, re-enable the slider - and let it be.
        this.overridden = false
        this.internalMax = this.max
      }
      this.$emit('input', +value)
    }
  }

  get isLocked () {
    return this.lockState
  }

  set isLocked (val: boolean) {
    this.lockState = val
    this.$emit('update:locked', val)
  }

  @Watch('locked')
  onLockedChange (val: boolean) {
    this.lockState = val
  }

  get isMobile () {
    return this.$vuetify.breakpoint.mobile
  }

  get textRules () {
    // Apply a min and max rule as per the slider.
    const rules = [
      ...this.rules,
      (v: string) => +v >= this.min || this.$t('app.general.simple_form.error.min', { min: this.min })
    ]
    if (!this.overridable) {
      rules.push(
        (v: string) => +v <= this.max || this.$t('app.general.simple_form.error.max', { max: this.max })
      )
    }
    return rules
  }

  mounted () {
    this.lockState = this.locked
  }

  handleChange (value: string | number) {
    value = +value
    if (
      value !== this.value &&
      !this.pending
    ) {
      if (this.valid) {
        this.pending = true
        this.$emit('change', value)
      } else {
        this.internalValue = this.value
      }
      this.lockState = this.locked
    }
  }

  handleReset () {
    this.internalValue = this.resetValue
    this.lockState = this.locked
    this.$emit('change', this.resetValue)
  }

  get isScreen () {
    return this.$vuetify.breakpoint.sm
  }

  keyboardChange (val: number) {
    this.internalValue = val
    this.$emit('change', this.internalValue)
  }
}
</script>
